TypeScript · 4336 bytes Raw Blame History
1 'use client';
2
3 import { useState, useEffect } from 'react';
4 import Link from 'next/link';
5 import { useParams } from 'next/navigation';
6 import { getConflicts, getPeopleByConflict, Conflict, Person } from '@/lib/api';
7 import Header from '@/components/Header';
8
9 export default function ConflictPage() {
10 const params = useParams();
11 const conflictId = parseInt(params.id as string);
12
13 const [conflict, setConflict] = useState<Conflict | null>(null);
14 const [people, setPeople] = useState<Person[]>([]);
15 const [loading, setLoading] = useState(true);
16 const [error, setError] = useState<string | null>(null);
17
18 useEffect(() => {
19 async function fetchData() {
20 try {
21 const conflicts = await getConflicts();
22 const currentConflict = conflicts.find(c => c.id === conflictId);
23
24 if (!currentConflict) {
25 throw new Error('Conflict not found');
26 }
27
28 setConflict(currentConflict);
29 const peopleData = await getPeopleByConflict(conflictId);
30 setPeople(peopleData);
31 } catch (err) {
32 setError(err instanceof Error ? err.message : 'Failed to load data');
33 console.error(err);
34 } finally {
35 setLoading(false);
36 }
37 }
38
39 fetchData();
40 }, [conflictId]);
41
42 if (loading) {
43 return (
44 <div className="min-h-screen bg-vmi-cream flex items-center justify-center">
45 <p className="text-gray-600 text-xl">Loading...</p>
46 </div>
47 );
48 }
49
50 if (error || !conflict) {
51 return (
52 <div className="min-h-screen bg-vmi-cream flex items-center justify-center">
53 <div className="text-center">
54 <p className="text-red-600 mb-4 text-xl">{error || 'Conflict not found'}</p>
55 <Link href="/" className="text-vmi-red hover:text-vmi-dark-red underline font-semibold">
56 Return to Home
57 </Link>
58 </div>
59 </div>
60 );
61 }
62
63 return (
64 <div className="min-h-screen bg-vmi-cream">
65 <Header
66 breadcrumbs={[
67 { label: 'Home', href: '/' },
68 { label: conflict.name }
69 ]}
70 />
71
72 {/* Main Content */}
73 <main className="max-w-6xl mx-auto px-4 py-12">
74 {/* Conflict Header */}
75 <div className="bg-vmi-light-gold border-2 border-vmi-gold rounded-lg p-8 mb-12 shadow-xl">
76 <h1 className="text-4xl font-black text-vmi-red mb-4">
77 {conflict.name}
78 </h1>
79 <p className="text-xl text-gray-700 mb-4">
80 {conflict.start_year} {conflict.end_year || 'Present'}
81 </p>
82 {conflict.description && (
83 <p className="text-gray-800 leading-relaxed mb-6">{conflict.description}</p>
84 )}
85 <div className="border-t-2 border-vmi-gold pt-6">
86 <p className="text-2xl font-bold text-vmi-red">
87 {conflict.casualty_count} VMI Alumni Gave Their Lives
88 </p>
89 </div>
90 </div>
91
92 {/* People List */}
93 <div className="bg-white border-2 border-gray-300 rounded-lg p-8 shadow-xl">
94 <h2 className="text-3xl font-bold mb-8 text-center text-vmi-red">
95 Honor Roll
96 </h2>
97
98 {people.length === 0 ? (
99 <p className="text-center text-gray-600 text-lg">No casualties recorded yet.</p>
100 ) : (
101 <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
102 {people.map((person) => (
103 <Link
104 key={person.id}
105 href={`/memorial/person/${person.id}`}
106 className="block p-6 border-2 border-gray-200 rounded-lg hover:border-vmi-gold hover:bg-vmi-light-gold transition-all duration-200 group"
107 >
108 <h3 className="text-xl font-bold text-gray-800 group-hover:text-vmi-red transition-colors mb-2">
109 {person.full_display_name || person.display_name}
110 </h3>
111 {person.rank && (
112 <p className="text-gray-700 font-semibold">{person.rank}</p>
113 )}
114 {person.unit && (
115 <p className="text-gray-600 text-sm italic">{person.unit}</p>
116 )}
117 </Link>
118 ))}
119 </div>
120 )}
121 </div>
122 </main>
123 </div>
124 );
125 }